<cfcomponent>
	<!--- NOTES --->
	<!---
		you should take care if you need to override onCFCrequest || onRequest
		other methods are, hopefully, straight-forward
		in general, it's better to have loved and lost- wait, sorry, it's better to write an event handler than override these methods
			include event triggers throughout this as necessary
		don't forget to call super.whatMethod() and pass it the correct arguments when overriding...
	--->
	<!--- NOTES --->

	<!--- FRAMEWORK REQUIRED SETTINGS --->
	<cfset this.applicationTimeout = createTimeSpan(0,1,0,0)>
	<cfset this.path = getApplicationRootPath()>
	<cfset initFile = "#this.path#/app/application.ini">

	<cfset this.customtagpaths = "#this.path#/tags">
	<cfset this.sessionManagement = true>
	<cfset this.sessionTimeout = createTimeSpan(0,0,30,0)>
	<cfset this.setClientCookies = true>
	<!--- FRAMEWORK REQUIRED SETTINGS --->

	<!---
		the following settings should be edited in the installer
		...or you can edit *** app/application.ini ***
	--->
	<cfset doClientScope = getProfileString(initFile, "database", "clientManagement")>
	<cfset this.clientmanagement = doClientScope>
	<cfif doClientScope>
		<cfset this.clientStorage = getProfileString(initFile, "database", "clientStorage")>
	</cfif>
	<cfset this.datasource = getProfileString(initFile, "database", "datasource")>
	<cfset this.debugIPaddress = getProfileString(initFile, "application", "debugIPaddress")>
	<cfset this.loginStorage = getProfileString(initFile, "application", "loginStorage")>
	<cfset this.name = getProfileString(initFile, "application", "name")>
	<cfset this.scriptProtect = getProfileString(initFile, "application", "name")>

	<!--- ORM Settings --->
	<cfset this.ormenabled = getProfileString(initFile, "ORM", "ormenabled")>
	<cfset this.ormsettings = {
		autorebuild = getProfileString(initFile, "ORM", "autorebuild"),
		cfclocation = getProfileString(initFile, "ORM", "cfclocation"),
		dbcreate = getProfileString(initFile, "ORM", "dbcreate"),
		dialect = getProfileString(initFile, "ORM", "dialect"),
		eventHandling = getProfileString(initFile, "ORM", "eventHandling")
	}>

<!---  --->
	<cffunction name="getApplicationRootPath" returntype="string" hint="Returns the root path of the acting Application.cfc file." output="false" access="public">
		<!--- <cf_shoutOut author="Pete Freitag">, http://www.petefreitag.com/item/630.cfm --->
		<cfargument name="base_path" default="./" hint="Normally you want to leave this as default" required="false">

		<cfset var actual_path = ExpandPath(arguments.base_path)>

		<cfif FileExists(ExpandPath(arguments.base_path & "Application.cfc"))>
			<cfreturn actual_path>
		<cfelseif REFind(".*[/\\].*[/\\].*", actual_path)>
			<cfreturn getApplicationRootPath("../#arguments.base_path#")>
		<cfelse>
		<!--- we have reached the root dir, so throw an error not found --->
		<cfthrow message="Unable to determine Application Root Path" detail="#actual_path#">
		</cfif>
	</cffunction>
<!---  --->
	<cffunction access="public" name="onApplicationStart" output="false" returntype="boolean">
		<cflock scope="Application" throwontimeout="true" timeout="17" type="exclusive">
			<cfset application.apiCache = structNew()>

			<!--- my way of trapping errors and debug values (especially when AJAXing), very helpful if the log doesn't give enough info --->
			<cfset application.debugLog = arrayNew(1)>
			<cfset application.errorLog = arrayNew(1)>

			<cfset application.debugIPaddress = this.debugIPaddress>
			<cfset application.dotPath = "cfmaker.">	<!--- MAKE THIS AN EMPTY STRING IF NECESSARY --->
			<cfset application.name = this.name>
			<cfset application.path = this.path>
			<cfset application.URL = "http://#CGI.http_host#/cfmaker">

			<!--- BE SURE TO TOGGLE THIS AS NEEDED --->
			<cfset application.developmentMode = true>
			<!--- DEVELOPMENT MODE SWITCH --->
		</cflock>

		<!--- obviously these two listeners need to be here if they're going to get fired --->
		<cf_addEventListener event="applicationStart" component="cfmaker.handler.init" method="initApp">	<!--- this event sets up the event registry and is where you [should] add event listeners --->
		<cf_addEventListener event="applicationStart" component="cfmaker.handler.framework" method="initApp">
		<cf_triggerEvent event="applicationStart">

		<cflog application="true" log="Application" text="#application.name# restarted at #now()#" type="warning">

		<cfreturn true>
	</cffunction>
<!---  --->
	<cffunction access="public" name="onApplicationEnd" output="false" returntype="void">
		<cfargument default="#structNew()#" name="applicationScope" required="false" type="struct">
		<!--- you shouldn't need to extend this method, just handle the applicationEnd event --->

		<cf_triggerEvent event="applicationEnd" values=#arguments.applicationScope#>

		<cfreturn true>
	</cffunction>
<!---  --->
	<cffunction access="public" name="onSessionStart" output="false" returntype="void">
		<cfparam default="0" name="session.userID">
		<cfparam default="" name="session.view">

		<cflock scope="Session" throwontimeout="true" timeout="7" type="exclusive">
			<cfset session.set = application.globalFunctions.set>
		</cflock>

		<cf_triggerEvent event="sessionStart">
	</cffunction>
<!---  --->
	<cffunction name="onSessionEnd" access="public" returntype="void" output="false">
		<cfargument default="#StructNew()#" name="applicationScope" required="false" type="struct">
		<cfargument name="sessionScope" type="struct" required="true">

		<cf_triggerEvent event="sessionEnd">
	</cffunction>
<!---  --->
<!---
	This method is not included because I don't like calling super in the middle of the function
	<cffunction name="onCFCRequest" access="public" returntype="any" output="true">
	    <cfargument name="component" type="string" required="true">
	    <cfargument name="methodName" type="string" required="true">
		<cfargument name="methodArguments" type="struct" required="true">

    </cffunction>
--->
<!---  --->
	<cffunction name="onCFCRequest" access="public" returntype="any" output="true">
	    <cfargument name="component" type="string" required="true">
	    <cfargument name="methodName" type="string" required="true">
		<cfargument name="methodArguments" type="struct" required="true">

		<cfset var binaryResponse = "">
	    <cfset var thisCFC = createObject("component", arguments.component)>	<!--- REMOVE THIS LINE FOR PRODUCTION --->

	    <cfset var CFCresult = "">
		<cfset var comMeta = getMetaData(thisCFC[arguments.methodName])>
	    <cfset var responseData = "">
	    <cfset var responseMIMEtype = "text/plain">

		<cfset loadGlobalFunctions()>

		<cf_triggerEvent event="CFCrequestStart">

<!---	USE THE FOLLOWING CODE-BLOCK FOR A PRODUCTION SYSTEM: COMMENT/REMOVE THE INDICATED LINES AFTER THIS BLOCK
		<!--- here we are caching the the component in application scope so it's later available --->
		<cfif !structKeyExists(application.apiCache, arguments.component)>
			<cfset application.apiCache[arguments.component] = createObject("component", arguments.component).init()>
		</cfif>

	    <cfinvoke returnvariable="CFCresult" component="#application.apiCache[arguments.component]#" method="#arguments.methodName#" argumentcollection="#arguments.methodArguments#">
--->

	    <cfinvoke component="#thisCFC#" method="#arguments.methodName#" returnvariable="CFCresult" argumentcollection="#arguments.methodArguments#">	<!--- REMOVE THIS LINE FOR PRODUCTION --->

		<cf_triggerEvent event="CFCrequestEnd">

		<cfif isDefined("CFCresult")>
		    <cfreturn CFCresult>
		<cfelse>
			<cfreturn>
		</cfif>
    </cffunction>
<!---  --->
	<cffunction access="public" name="onRequestStart" returnType="boolean">
	    <cfargument type="String" name="targetPage" required="true">

		<cfset var I = "">
		<cfset var controllerMeta = "">
		<cfset var context = "">
		<cfset var reinitialize = false>
		<cfset var slashPos = 0>

		<!---
			initialize our request context struct when the view changes
			this needs to persist as long as the view is active, hence the
		--->
		<cfset session.set("request", request)>	<!--- gives us a "pointer" to the request scope so we use it for semi-generalization --->

		<cfset loadGlobalFunctions()>

		<cfif structCount(URL)>
			<cfset handleURLvars(URL)>
		</cfif>

		<cfif isDefined("CGI.path_info") AND len(CGI.path_info)>
			<cfset setupView(CGI.path_info)>
		</cfif>

		<!--- NOTE: the requestStart event fires before any request-specific action is taken --->
		<cf_triggerEvent event="requestStart" page="#arguments.targetPage#">

	    <cfreturn true>
	</cffunction>
<!---  --->
	<cffunction name="onRequest" returnType="void">
		<!--- you shouldn't need to override this method...it builds each page and includes non-framework pages when no view is specified in the URLpath --->
	    <cfargument name="targetPage" type="String" required=true/>

		<cfset var JSadd = ".min">

		<cfif isDefined("form.ORM")>
			<!--- ...which includes a potential implicit event for an ORM submission via form-scope --->
			<cfset catchORMformSubmit(form)>
		</cfif>

		<cfif isDefined("CGI.path_info") AND len(CGI.path_info)>
			<cfif directoryExists(session.viewPath)>
				<!--- NOTE: this event handler will fire on EVERY view load --->
				<cf_triggerEvent event="preView">

				<cfif isDefined("session.context.preView") AND session.context.preView>
					<cfinvoke component="session.controller" method="preView">
				</cfif>

				<cfoutput>
					<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
	   "http://www.w3.org/TR/html4/loose.dtd">
					<html>
						<head>
							<title>CFmaker</title>

							<link href="#application.URL#/app/css/jquery-ui-1.7.2.custom.css" rel="stylesheet">	<!--- optional --->
							<link href="#application.URL#/app/css/application.css" rel="stylesheet">
							<link href="#application.URL#/view/#session.view#/styles.css" rel="stylesheet">

							<cfajaximport>
							<cfajaxproxy cfc="#application.dotPath#app.appProxy" jsclassname="applicationProxy">
							<cfajaxproxy cfc="#application.dotPath#view.#session.view#.controller" jsclassname="controllerProxy">
							<cfajaxproxy cfc="#application.dotPath#view.#session.view#.display" jsclassname="displayProxy">

							<!---
								scripts loaded for every view, including full versions for development mode
								jquery core is required
								jquery-ui not required but is used in bundled views
									if you download a custom theme you can just copy/overwrite the CSS and images directory
									if you use a pre-rolled theme then you migh have to change the js filename in the script tag below

								obviously, it's up to the developer to provide a minified version of view scripts, or just use the full js
									try: http://closure-compiler.appspot.com/home
									it's strongly advised to do so...in addition, you might consider rolling all js into one file (or using $.getScript())
							--->

							<cfif application.developmentMode>
								<cfset JSadd = "">
							</cfif>

								<script language="JavaScript" src="#application.URL#/app/js/jquery-1.4#JSadd#.js" type="text/javascript"></script>
								<!--- mini version here...full version is not a single file, so... --->
								<script language="JavaScript" src="#application.URL#/app/js/jquery-ui-1.7.2.custom#JSadd#.min.js" type="text/javascript"></script>
								<!--- jquery-ui-1.7.2.custom.min.js --->
								<script language="JavaScript" src="#application.URL#/app/js/application#JSadd#.js" type="text/javascript"></script>
								<script language="JavaScript" src="#application.URL#/app/js/jquery.CFmaker#JSadd#.js" type="text/javascript"></script>
								<script language="JavaScript" src="#application.URL#/app/js/jquery.hotkeys#JSadd#.js" type="text/javascript"></script>
								<script language="JavaScript" src="#application.URL#/app/js/jquery.mousewheel#JSadd#.js" type="text/javascript"></script>
								<script language="JavaScript" src="#application.URL#/view/#session.view#/script#JSadd#.js" type="text/javascript"></script>
						</head>

						<body>
							#session.display.mainContent()#
						</body>
					</html>
				</cfoutput>

				<cfif isDefined("session.context.postView") AND session.context.postView>
					<cfinvoke component="session.controller" method="postView">
				</cfif>
			<cfelse>
				<!---
					if we get this far we know that the user has requested a view, but it doesn't exist...yet
					trigger an event, ostensibly an application view editor (like the bundled creator view)
				--->
				<cf_triggerEvent event="missingView" view="#session.view#">
			</cfif>
		<cfelse>
			<cfinclude template="#arguments.targetPage#">
		</cfif>
	</cffunction>
<!---  --->
	<cffunction name="onRequestEnd" access="public" returntype="void" output="true">
		<!--- NOTE: this event will fire on every view load --->
		<cf_triggerEvent event="postView">
	</cffunction>
<!---  --->
<!---
	This method isn't provided because it's use is highly customized per application/company so...see Application.cfc
	<cffunction name="onError" access="public" returntype="void" output="true">
		<cfargument name="exception" type="any" required="true">
		<cfargument name="eventName" type="string" required="false" default="">

	</cffunction>
--->
<!---  --->
	<cffunction name="onMissingTemplate" access="public" returnType="boolean" output="false">
   		<cfargument type="string" name="targetPage" required=true>

   		<cf_triggerEvent event="missingTemplate" targetPage="#arguments.targetPage#" context="#request#">

		<cfreturn true>
	</cffunction>
<!---  --->
<!---  --->
	<cffunction name="cleanViewPath" access="private">
		<cfargument name="path" required="true" type="string">
		<!---
			a valid viewPath looks like ~ debug || myView/myOtherView
			this corresponds to a sub-directory of /view (e.g. view/debug || view/myView/myOtherView)
		--->

		<!--- only allow alphanumerics (technically too conservative but...) --->
		<cfset result = rereplace(arguments.path, "/^[0-9A-Za-z]+$/", "")>

		<!--- if the leading char is a / then strip it --->
		<cfif left(result, 1) EQ "/">
			<cfset result = right(arguments.path, len(arguments.path) - 1)>
		</cfif>

		<!--- if the trailing char is a / then strip it --->
		<cfif right(result, 1) EQ "/">
			<cfset result = left(arguments.path, len(arguments.path) - 1)>
		</cfif>

		<cfreturn result>
	</cffunction>
<!---  --->
	<cffunction name="handleURLvars" access="private">
		<cfargument name="URLscope" required="true" type="struct">

		<!--- change the following <cfif> line to change access to this functionality... --->
		<cfif application.developmentMode OR (listContains(application.debugIPaddress, CGI.remote_addr))>
			<cfif isDefined("arguments.URLscope.reload")>
				<!--- this causes a reload of all event listeners --->
				<cf_triggerEvent event="applicationStart">
			</cfif>

			<cfif isDefined("arguments.URLscope.restart")>
				<cfset applicationStop()>
			</cfif>
		</cfif>
	</cffunction>
<!---  --->
	<cffunction name="loadGlobalFunctions">
		<!---
			copy the methods into the variables scope
		--->
		<cfloop array="#application.globalFunctionMeta.functions#" index="I">
			<cfset evaluate("variables.#I.name# = application.globalFunctions.#I.name#")>
		</cfloop>

		<cfif isDefined("session.controller")>
			<cfset variables.controller = session.controller>
		</cfif>

		<cfif isDefined("session.display")>
			<cfset variables.display = session.display>
		</cfif>
	</cffunction>
<!---  --->
	<cffunction name="setupController" access="private">
		<!---
			if the controller CFC exists then we load it into memory
			we use the session scope so it will be available to AJAX requests within this view
		--->
		<cfset session.set("controller", createObject("component", "#session.controllerPath#").init())>
		<cfset controllerMeta = getComponentMetadata("#session.controllerPath#")>

		<cfif isDefined("controllerMeta.functions")>
			<!---
				see what standard methods are in the controller
				note: auto-invoked controller functions take no arguments
					they are intended to handle form and request data and do general tasks
			--->
			<cfloop array="#controllerMeta.functions#" index="I">
				<cfswitch expression="#I.name#">
					<cfcase value="preView">	<!--- preView will run before the view is loaded --->
						<cfset session.context.preView = true>
					</cfcase>
					<cfcase value="preRequest">	<!--- preRequest runs after every request within this view (even AJAX/subViews) --->
						<cfset session.context.preRequest = true>
					</cfcase>
					<cfcase value="postRequest">	<!--- postRequest runs after every request within this view (even AJAX/subViews) --->
						<cfset session.context.postRequest = true>
					</cfcase>
					<cfcase value="postView">	<!--- postView runs after the view is loaded --->
						<cfset session.context.postView = true>
					</cfcase>
				</cfswitch>
			</cfloop>
		</cfif>
	</cffunction>
<!---  --->
	<cffunction name="setupDisplay" access="private">
		<cfset session.set("display", createObject("component", "#session.displayPath#").init())>
	</cffunction>
<!---  --->
	<cffunction name="setupView" access="private">
		<cfargument name="pathInfo" required="true" type="string">

		<cflock scope="Session" throwontimeout="true" timeout="7" type="exclusive">
			<!--- normally, I would use session.set, but for a block of writes we'll do this --->
			<cfset session.context = #structNew()#>
			<cfset session.context.preRequest = false>
			<cfset session.context.postRequest = false>
			<cfset session.context.preView = false>
			<cfset session.context.postView = false>

			<cfset session.view = cleanViewPath(arguments.pathInfo)>

			<cfset session.viewPath = "#application.path#/view/#session.view#">

			<cfset session.controllerPath = "#application.dotPath#view.#session.view#.controller">
			<cfset session.controllerTemplate = replace("#application.path#/view/#session.view#/controller.cfc", "\", "/", "all")>

			<cfset session.displayPath = "#application.dotPath#view.#session.view#.display">
			<cfset session.displayTemplate = replace("#application.path#/view/#session.view#/display.cfc", "\", "/", "all")>
		</cflock>

		<cfif fileExists("#session.controllerTemplate#")>
			<cfset setupController()>
		</cfif>

		<cfif fileExists("#session.displayTemplate#")>
			<cfset setupDisplay()>
		</cfif>
	</cffunction>
</cfcomponent>